/*
   Copyright (c) [Year] [name of copyright holder]
   [Software Name] is licensed under Mulan PSL v2.
   You can use this software according to the terms and conditions of the Mulan PSL v2. 
   You may obtain a copy of Mulan PSL v2 at:
            http://license.coscl.org.cn/MulanPSL2 
   THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.  
   See the Mulan PSL v2 for more details.  
*/

#ifndef JIAJIA_VALUE_HPP
#define JIAJIA_VALUE_HPP

#include"cstring"

namespace jiajia{
    
    class value{
    public:
        using boolType = bool;
        using intType = long long;
        using realType = double;
        using strType = my::ustring;
        using seqType = my::seq<value>;
        using varType = var<value>;
        using tableType = table<value>;

        // 最多 8 个属性
        enum VALUEATTRENUM{
            TYPE = 0,       // 类型属性，存储值的类型
            MARK,           // 值的标识
            ATTREND = 8,
        };

        enum VALUETYPEENUM{
            TYPE_BEGIN = 0,
            INVALIDTYPE = TYPE_BEGIN,   // 无效类型
            BOOLTYPE,                   // 布尔类型
            REALTYPE,                   // 浮点类型
            STRINGTYPE,                 // 字符串类型
            SEQTYPE,                    // 数组类型
            TABLETYPE,                  // 表类型
            TYPE_END
        };

        enum VALUEMARKENUM{
            MARK_BEGIN = 0,
            NORMALMARK = MARK_BEGIN,
            REFMARK,
            CONSTMARK,
            IMMUTABLEMARK,
            MARK_END
        };

        enum_t Attr[ATTREND];
        union{
            boolType Bool;
            realType Real;
            strType * Str;
            seqType * Seq;
            tableType * Table;
            value * Ref;
        };

        // 类型比较规则
        static const int TypeCompSeq[TYPE_END][TYPE_END];

        static int comp(const value & lhs, const value & rhs){
            enum_t t1 = lhs.getType();
            enum_t t2 = rhs.getType();
            if(t1 == t2){
                switch(t1){
                case BOOLTYPE: return my::func<boolType>::comp(lhs.getBool(), rhs.getBool());
                case REALTYPE: return my::func<realType>::comp(lhs.getReal(), rhs.getReal());
                case STRINGTYPE: return my::func<strType>::comp(lhs.getStr(), rhs.getStr());
                case SEQTYPE: return my::func<seqType *>::comp(&lhs.getSeq(), &rhs.getSeq());
                case TABLETYPE: return my::func<tableType *>::comp(&lhs.getTable(), &rhs.getTable());
                default : return 0;
                }
            }

            return TypeCompSeq[t1][t2];
        }

        value(){
            Attr[TYPE] = INVALIDTYPE;
            Attr[MARK] = NORMALMARK;
            Bool = false;
        }

        // 记住，赋值语句和移动语句都不是给加加语法用的。
        // 而是给数组或者表调整时候移动赋值时候用的。
        // 加加的赋值语句请用 set 。
        value(const value & val):Bool(false){
            if(val.Attr[MARK] == REFMARK){
                Ref = mem::up(val.Ref);
            }else{
                switch(Attr[TYPE]){
                case INVALIDTYPE: break;
                case BOOLTYPE: Bool = val.Bool; break;
                case REALTYPE: Real = val.Real; break;
                case STRINGTYPE: Str = mem::up(val.Str); break;
                case SEQTYPE: Seq = mem::up(val.Seq); break;
                case TABLETYPE: Table = mem::up(val.Table); break;
                default: break;
                }
            }

            Attr[TYPE] = val.Attr[TYPE];
            Attr[MARK] = val.Attr[MARK];
        }

        value & operator=(const value & val){
            if(this == &val) return *this;

            free();

            if(val.Attr[MARK] == REFMARK){
                Ref = mem::up(val.Ref);
            }else{
                switch(Attr[TYPE]){
                case INVALIDTYPE: break;
                case BOOLTYPE: Bool = val.Bool; break;
                case REALTYPE: Real = val.Real; break;
                case STRINGTYPE: Str = mem::up(val.Str); break;
                case SEQTYPE: Seq = mem::up(val.Seq); break;
                case TABLETYPE: Table = mem::up(val.Table); break;
                default: break;
                }
            }
            Attr[TYPE] = val.Attr[TYPE];
            Attr[MARK] = val.Attr[MARK];

            return *this;
        }

        value(value && val){
            if(val.Attr[MARK] == REFMARK){
                Ref = val.Ref;
            }else{
                switch(val.Attr[TYPE]){
                case INVALIDTYPE: break;
                case BOOLTYPE: Bool = val.Bool; break;
                case REALTYPE: Real = val.Real; break;
                case STRINGTYPE: Str = val.Str; break;
                case SEQTYPE: Seq = val.Seq; break;
                case TABLETYPE: Table = val.Table; break;
                default: break;
                }
            }
            Attr[TYPE] = val.Attr[TYPE];
            Attr[MARK] = val.Attr[MARK];

            val.Attr[TYPE] = INVALIDTYPE;
            val.Attr[MARK] = NORMALMARK;
            val.Bool = false;
        }

        value & operator=(value && val){
            if(this == &val) return *this;

            free();

            if(val.Attr[MARK] == REFMARK){
                Ref = val.Ref;
            }else{
                switch(val.Attr[TYPE]){
                case INVALIDTYPE: break;
                case BOOLTYPE: Bool = val.Bool; break;
                case REALTYPE: Real = val.Real; break;
                case STRINGTYPE: Str = val.Str; break;
                case SEQTYPE: Seq = val.Seq; break;
                case TABLETYPE: Table = val.Table; break;
                default: break;
                }
            }
            Attr[TYPE] = val.Attr[TYPE];
            Attr[MARK] = val.Attr[MARK];

            val.Attr[TYPE] = INVALIDTYPE;
            val.Attr[MARK] = NORMALMARK;
            val.Bool = false;
            return *this;
        }

        void refto(value * val){
            if(val == nullptr) return;

            free();
            if(Attr[MARK] == REFMARK){
                Ref = mem::up(val->Ref);
            }else{
                Ref = mem::up(val);
            }

            Attr[TYPE] = val->Attr[TYPE];
            Attr[MARK] = REFMARK;
        }

        inline const enum_t getType() const {
            return Attr[TYPE];
        }

        inline void set(value & val){
            if(Attr[MARK] == IMMUTABLEMARK) return ;

            switch(val.Attr[TYPE]){
            case INVALIDTYPE:
                free();
                break;
            case BOOLTYPE:
                setBool(val.getBool());
                break;
            case REALTYPE:
                setReal(val.getReal());
                break;
            case STRINGTYPE:
                if(val.Attr[MARK] == CONSTMARK){
                    setStr(std::move(val.getStr()));
                }else
                    setStr(*(val.Str));
                break;
            case SEQTYPE:
                setSeq(&val.getSeq());
                break;
            case TABLETYPE:
                setTable(&val.getTable());
                break;
            default: break;
            }
        }
   
        inline void setBool(const boolType v){
            if(Attr[MARK] == IMMUTABLEMARK) return ;

            if(Attr[MARK] == REFMARK)
                Ref->setBool(v);
            else{
                free();
                Bool = v;
            }

            Attr[TYPE] = BOOLTYPE;
        }

        void setReal(const realType v){
            if(Attr[MARK] == IMMUTABLEMARK) return ;

            if(Attr[MARK] == REFMARK)
                Ref->setReal(v);
            else{
                free();
                Real = v;
            }
            Attr[TYPE] = REALTYPE;
        }

        void setStr(const my::unicode_t * buf){
            if(Attr[MARK] == IMMUTABLEMARK) return ;

            if(Attr[MARK] == REFMARK){
                Ref->setStr(buf);
            }else{
                if(Attr[TYPE] != STRINGTYPE){
                    free();
                    Str = mem::calloc<strType>(1);
                }
                *Str = buf;
                Attr[MARK] = NORMALMARK;
            }
            Attr[TYPE] = STRINGTYPE;
        }

        void setStr(strType && str){
            if(Attr[MARK] == IMMUTABLEMARK) return ;

            if(Attr[MARK] == REFMARK){
                Ref->setStr(std::move(str));
            }else{
                if(Attr[TYPE] != STRINGTYPE){
                    free();
                    Str = mem::calloc<strType>(1);
                }
                *Str = std::move(str);
                Attr[MARK] = NORMALMARK;
            }
            Attr[TYPE] = STRINGTYPE;            
        }

        void setStr(const strType & str){
            if(Attr[MARK] == IMMUTABLEMARK) return ;

            if(Attr[MARK] == REFMARK){
                Ref->setStr(str);
            }else{
                if(Attr[TYPE] != STRINGTYPE){
                    free();
                    Str = mem::calloc<strType>(1);
                }
                *Str = str;
                Attr[MARK] = NORMALMARK;
            }

            Attr[TYPE] = STRINGTYPE;
        }

        void setSeq(seqType * seq){
            if(Attr[MARK] == IMMUTABLEMARK) return ;
            seq = mem::up(seq);

            if(Attr[MARK] == REFMARK){
                Ref->setSeq(seq);
            }else{
                free();
                Seq = mem::up(seq);
                Attr[MARK] = NORMALMARK;
            }

            Attr[TYPE] = SEQTYPE;
        }

        void setTable(tableType * table){
            if(Attr[MARK] == IMMUTABLEMARK) return ;
            table = mem::up(table);

            if(Attr[MARK] == REFMARK){
                Ref->setTable(table);
            }else{
                free();
                Table = table;
                Attr[MARK] = NORMALMARK;
            }

            Attr[TYPE] = TABLETYPE;
        }

        // 设置一些常量的值
        inline void setConstBool(const boolType v){
            this->setBool(v);
            Attr[MARK] = CONSTMARK;
        }

        inline void setConstReal(const realType v){
            this->setReal(v);
            Attr[MARK] = CONSTMARK;
        }

        inline void setConstStr(const strType & str){
            this->setStr(str);
            Attr[MARK] = CONSTMARK;
        }

        inline boolType getBool() const {
            if(Attr[MARK] == REFMARK)
                return (*Ref).getBool();
            return Bool;
        }

        inline realType getReal() const {
            if(Attr[MARK] == REFMARK)
                return (*Ref).getReal();
            return Real;
        }

        inline strType & getStr() const {
            if(Attr[MARK] == REFMARK)
                return (*Ref).getStr();
            return *Str;
        }

        inline seqType & getSeq() const {
            if(Attr[MARK] == REFMARK)
                return (*Ref).getSeq();
            return *Seq;
        }

        inline tableType & getTable() const {
            if(Attr[MARK] == REFMARK)
                return (*Ref).getTable();
            return *Table;
        }

        inline void immutable(){
            if(Attr[MARK] != REFMARK)
                Attr[MARK] = IMMUTABLEMARK;
        }

        // 转换函数
        bool toBool(boolType & b){
            if(Attr[MARK] == REFMARK){
                return (*Ref).toBool(b);
            }else{
                switch(Attr[TYPE]){
                case INVALIDTYPE:
                    b = false;
                    break;
                case BOOLTYPE:
                    b = getBool();
                    break;
                case REALTYPE:
                    b = (getReal() != 0.0);
                    break;
                default: return false;
                }
            }
            return true;
        }

        bool toReal(realType & r){
            if(Attr[MARK] == REFMARK){
                return (*Ref).toReal(r);
            }else{
                switch(Attr[TYPE]){
                case INVALIDTYPE:
                    r = 0.0;
                    break;
                case BOOLTYPE:
                    r = static_cast<realType>(getBool());
                    break;
                case REALTYPE:
                    r = getReal();
                    break;
                default: return false;
                }
            }
            return true;

        }

        bool toString(std::string & s){
            bool flag = true;
            if(Attr[MARK] == REFMARK){
                return (*Ref).toString(s);
            }else{
                switch(Attr[TYPE]){
                case INVALIDTYPE:
                    s.append("null");
                    break;
                case BOOLTYPE:
                    s.append((this->getBool())? "true":"false");
                    break;
                case REALTYPE:
                    s.append(std::to_string(this->getReal()));
                    break;
                case STRINGTYPE:{
                    s.append("\"");
                    this->getStr().each([](my::unicode_t u, std::string & s)->bool{
                                            switch(u){
                                            case L'@': s.append("@@"); break;
                                            case L'\n': s.append("@回车"); break;
                                            case L'\t': s.append("@制表"); break;
                                            case L'\"': s.append("@\""); break;
                                            case L'“': s.append("@“"); break;
                                            case L'”': s.append("@”"); break;
                                            case my::unicode::eof: s.append("@eof"); break;
                                            default: s.append(my::utf8::UnicodeToStr(u)); break;
                                            }
                                            return true;
                                        }, s);
                    s.append("\"");
                    }
                    break;
                case SEQTYPE:{
                    long size = this->getSeq().size();
                    s.append("{");
                    this->getSeq().each([&flag, &size](value & val, std::string & s)->bool{
                                            flag = val.toString(s);
                                            --size;
                                            if(size != 0)
                                                s.append("、");
                                            return flag;
                                        }, s);
                    s.append("}");
                }
                    break;
                case TABLETYPE:{
                    flag = this->getTable().toString(s);
                }
                    break;
                default:
                    flag = false;
                    break;
                }
            }
            return flag;
        }

        void free(){
            if(Attr[MARK] == REFMARK){
                mem::free(Ref);
            }else{
                switch(Attr[TYPE]){
                case INVALIDTYPE: break;
                case STRINGTYPE:
                    mem::free(Str);
                    break;
                case SEQTYPE:
                    mem::free(Seq);
                    break;
                case TABLETYPE:
                    mem::free(Table);
                    break;
                default: break;
                }
            }
            Attr[TYPE] = INVALIDTYPE;
            Attr[MARK] = NORMALMARK;
        }
    };

    // 类型比较规则 INVALIDTYPE < BOOLTYPE < REALTYPE < STRINGTYPE < SEQTYPE < TABLETYPE
    const int value::TypeCompSeq[TYPE_END][TYPE_END] = {
            // INVALIDTYPE: I, B, R, ST, SE, T
            {0, -1, -1, -1, -1, -1},
            // BOOLTYPE: I, B, R, ST, SE, T
            {1, 0, -1, -1, -1, -1},
            // REALTYPE: I, B, R, ST, SE, T
            {1, 1, 0, -1, -1, -1},
            // STRINGTYPE: I, B, R, ST, SE, T
            {1, 1, 1, 0, -1, -1},
            // SEQTYPE: I, B, R, ST, SE, T
            {1, 1, 1, 1, 0, -1},
            // TABLETYPE: I, B, R, ST, SE, T
            {1, 1, 1, 1, 1, 0},
    };

    bool operator==(const value & lhs, const value & rhs){
        return value::comp(lhs, rhs) == 0;
    }

    bool operator!=(const value & lhs, const value & rhs){
        return !(lhs == rhs);
    }

    bool operator>(const value & lhs, const value & rhs){
        return value::comp(lhs, rhs) > 0;
    }

    bool operator<(const value & lhs, const value & rhs){
        return value::comp(lhs, rhs) < 0;
    }

    bool operator>=(const value & lhs, const value & rhs){
        return value::comp(lhs, rhs) >= 0;
    }

    bool operator<=(const value & lhs, const value & rhs){
        return value::comp(lhs, rhs) <= 0;
    }

    // // 获取的是 t1 转向 t2 该用那种类型
    // // 不废话吗，t1 转 t2 肯定是用 t2 类型啊
    // // 所以该表应该是用来判断 t1 是否可以转成 t2 ???
    // // 没有卵用，浪费时间
    // inline static unsigned char TransformTable(unsigned char t1, unsigned char t2){
    //     /*
    //      *          无效    布尔    整型    浮点型  字符串  数组    表
    //      *  无效    无效    无效    无效    无效    无效    无效    无效
    //      *  布尔    无效    布尔    整型    浮点型  字符串  无效    无效        
    //      *  整数    无效    布尔    整型    浮点型  字符串  无效    无效
    //      *  浮点型  无效    布尔    整型    浮点型  字符串  无效    无效
    //      *  字符串  无效    布尔    整型    浮点型  字符串  无效    无效
    //      *  数组    无效    无效    无效    无效    无效    数组    无效
    //      *  表      无效    无效    无效    无效    无效    无效    表
    //      *
    //      */
    //     static unsigned char table[value::TYPEEND][value::TYPEEND] = {
    //         // 无效
    //         {value::INVALIDTYPE, value::INVALIDTYPE, value::INVALIDTYPE, value::INVALIDTYPE, value::INVALIDTYPE, value::INVALIDTYPE, value::INVALIDTYPE},            
    //         // 布尔
    //         {value::INVALIDTYPE, value::INVALIDTYPE, value::INVALIDTYPE, value::INVALIDTYPE, value::INVALIDTYPE, value::INVALIDTYPE, value::INVALIDTYPE},
    //         // 整型
    //         {value::INVALIDTYPE, value::BOOLTYPE, value::INTTYPE, value::REALTYPE, value::STRINGTYPE, value::INVALIDTYPE, value::INVALIDTYPE},
    //         // 浮点型
    //         {value::INVALIDTYPE, value::BOOLTYPE, value::INTTYPE, value::REALTYPE, value::STRINGTYPE, value::INVALIDTYPE, value::INVALIDTYPE},
    //         // 字符串
    //         {value::INVALIDTYPE, value::BOOLTYPE, value::INTTYPE, value::REALTYPE, value::STRINGTYPE, value::INVALIDTYPE, value::INVALIDTYPE},
    //         // 数组
    //         {value::INVALIDTYPE, value::INVALIDTYPE, value::INVALIDTYPE, value::INVALIDTYPE, value::INVALIDTYPE, value::SEQTYPE, value::INVALIDTYPE},
    //         // 表
    //         {value::INVALIDTYPE, value::INVALIDTYPE, value::INVALIDTYPE, value::INVALIDTYPE, value::INVALIDTYPE, value::INVALIDTYPE, value::TABLETYPE},
    //     };

    //     if(t1 >= value::TYPEBEGIN && t1 < value::TYPEEND &&
    //        t2 >= value::TYPEBEGIN && t2 < value::TYPEEND)
    //         return table[t1][t2];

    //     return value::INVALIDTYPE;
    // }
}

#endif
